hanabiapp.game.agent

Hanabiアプリ AI の作り方

  • 新しい AI 実装時には,必ず hanabiapp/game/agent/agent.py を継承してください.
  • 作成後,以下にAIのクラス名を記載ください. -- hanabiapp\game\agent\__init__.py: HanabiアプリがAIとして認識します. -- hanabiapp/config/ai_assignment.json: マッチング方式に合わせて記載して下さい.
  • 備考

    • tests/test_ai_simulation.pyを使用して,CUI環境でAI同士を対戦させることができます.
    • 詳細なマッチングルールはhanabiapp/views/game.pyを確認してください.

<入力>

AI が受け取る入力は 2 種類の形式に対応しています.

① Game クラス形式

これは,hanabiapp\game\game_manager.py 内の Game クラス直下の docstring に記載された形式です.
この場合,通信の際に HLE 形式に変換する必要があるため,エージェント実装時は need_hle_convert フラグを立ててください.

エージェントには,ゲームの状態全体を保持する Game クラスのインスタンス が引数として渡されます.
エージェントはこのインスタンス内の各属性を参照することで,自身の手札状況,対戦相手の手札(完全情報または観察可能情報),
ボードの状態,山札,捨て札,ヒントトークン数,カード知識(Knowledge)など,ゲーム進行に必要な情報を取得します.

主な属性と内容

  • game_const (GameConst インスタンス)
     各種定数(例:全色リスト ALL_COLORS,色名配列 COLOR_NAMES,カード枚数情報 COUNTS など)を保持します.

  • players (list)
     参加プレイヤーのリストです.各プレイヤーは,プレイヤー番号,名前などの基本情報を含みます.

  • hands (dict)
     各プレイヤーの手札を保持する辞書です.
     キーはプレイヤー番号(int),値は各手札内のカードのリスト(各カードはタプル形式,例:(色,数字))となります.
     ※ 対戦相手の手札については,全カード情報が保持されるが,自身の手札は観察時に隠蔽される場合があります.

  • deck (list)
     残りの山札です.各要素はカードを表すタプル(色,数字)となります.

  • trash (list)
     これまでに捨てられたカードのリストです.

  • board (dict)
     各色ごとのファイアワーク(花火)の進行状況を保持する辞書です.
     キーは色(例:"B","G","R","W","Y")で,値は現在の最大ランク(初期値は0,最大5)となります.

  • hints (int)
     現在残っているヒントトークンの数です.

  • max_hints (int)
     ヒントトークンの最大数(通常は8)です.

  • miss (int)
     現在残っているミス可能回数です.

  • max_miss (int)
     ミス可能回数の上限(通常は3)です.

  • extra_turns (int)
     山札切れ時に与えられる追加ターン数です.

  • knowledge_manager (KnowledgeManager インスタンス)
     各プレイヤーのカード知識を管理するためのオブジェクトです.

  • knowledge (list)
     各プレイヤーの手札に対する知識情報を保持するリストです.
     各要素は,該当プレイヤーの各カードに関する可能性(色・ランクの候補数など)を表します.

  • random (random.Random インスタンス)
     ゲーム内で利用される乱数生成器です.

  • タイミング情報
     以下の属性も保持されます.
     - turn:現在のターン数(内部カウンタ)
     - num_of_valid_actions:そのターンの有効なアクション数

  • その他
     ゲーム進行ログやデータ記録用のオブジェクト(data_manager,gui_log_history 等)も含まれますが,
     通常はエージェントの意思決定には直接関与しません.

エージェントは,上記の状態情報を元に,自身の手札(および対戦相手の手札)や,
ボード状況,山札,捨て札,ヒントトークン数,カード知識などを参照し,
次のアクションの決定に活用してください.


② HLE 形式

これは,Google の強化学習環境 (Hanabi Learning Environment,以下 HLE) に対応した入出力形式です.
hanabiapp\game\game_manager.py 内の create_observation 関数により作成されます.
詳細は以下のとおりです.

なお,本家Google の強化学習環境 は以下の参照してください. https://github.com/google-deepmind/hanabi-learning-environment/tree/master

観測データの構造

観測データは辞書(dict)形式で表現され,各キーの意味は以下の通りです.

  • current_player (int)
     現在のプレイヤーのインデックスを示します.

  • current_player_offset (int)
     観察者から見た現在のプレイヤーまでのオフセットを表します.
     例:観察者自身の場合は 0 となります.

  • deck_size (int)
     山札に残っているカードの枚数を表します.

  • discard_pile (list)
     これまでに捨てられたカードの一覧を表します.各要素はカード情報を表す辞書であり,
     {'color': 色, 'rank': 数字} の形式となります.

  • fireworks (dict)
     各色のファイアワーク(ボード上の進行状況)を表す辞書です.
     キーは色(例:"B","G","R","W","Y")で,値はその色の現在の最高ランク(整数)です.

  • information_tokens (int)
     現在残っているヒントトークンの数を示します.

  • legal_moves (list)
     現在の状態で取り得る合法なアクションの一覧を表します.
     各アクションは HLE 形式に変換された辞書であり,例えば以下の形式があります.
      - {'action_type': 'PLAY', 'card_index': X}
      - {'action_type': 'DISCARD', 'card_index': X}
      - {'action_type': 'REVEAL_COLOR', 'target_offset': Y, 'color': 'B'}
      - {'action_type': 'REVEAL_RANK', 'target_offset': Y, 'rank': Z}

  • life_tokens (int)
     残りのライフトークン(ミス可能回数)を示します.

  • observed_hands (list)
     各プレイヤーの手札情報を格納したリストです.
     観察者自身の手札は隠蔽され,各カードは {'color': None, 'rank': -1} で表現されます.
     他のプレイヤーの手札は,実際のカード情報を {'color': 色, 'rank': 数字} の形式で表します.
     ※ HLE 形式では,カードのランクは 0 から始まる点に注意してください.

  • num_players (int)
     ゲームに参加しているプレイヤーの総数を表します.

  • card_knowledge (list)
     各プレイヤーの手札に対する知識情報を格納したリストです.
     各カードの知識は辞書形式で表され,
     {'color': 色または None, 'rank': 数字または None} の形式となります.

補足

新規 AI の実装時には,HLE 形式の観測データから,上記の各項目を正しく抽出し,
自身の手札や対戦相手の手札,ボードの状況,山札,捨て札,ヒントトークン数,
合法なアクション等の情報を利用して,次に取るべきアクションを決定してください.

hanabiapp/game/agent/simple_agent.py は,HLE 形式の観測データを入力として受け取り,
シンプルなヒューリスティックに基づいてアクションを選択する実装例となっています.
新規 AI を HLE 形式で実装する場合は,参考としてご活用ください.


<出力>

action の定義

  • action_type str
     以下 4 択のうちいずれか.
      - PLAY:カードをプレイ
      - DISCARD:カードを捨てる
      - REVEAL_RANK:数字のヒントを出す
      - REVEAL_COLOR:色のヒントを出す

  • is_time_limit bool
     一手の制限時間に到達し,ランダムな行動をとったかどうかを示します.
     一手の制限時間に到達したならば True ,そうでないなら False です.

action_type が PLAY のとき

  • hand_index int
     自分の手札の左から何番目をプレイしたかを,0スタートのインデックスで指定します.

  • card str
     プレイしたカードが何であったかを記録します.
     例:青の4の場合は B4 と記録します.

  • is_success bool
     プレイに成功したか否かを示します.

action_type が DISCARD のとき

  • hand_index int
     自分の手札の左から何番目を捨てたかを指定します(0スタート).

  • card str
     捨てたカードが何であったかを記録します.
     例:青の4の場合は B4 と記録します.

action_type が REVEAL_RANK のとき

  • target_pid int
     ヒント対象(ターゲット)のプレイヤ ID を指定します.

  • target_hand_index str
     ターゲットの手札の左から何番目にヒントを出したかを,0スタートで指定します.
     複数枚にヒントを出す場合は,例として 0-1-4 のようにハイフン区切りで記載します.

  • rank int
     与える数字のヒントを指定します.

action_type が REVEAL_COLOR のとき

  • target_pid
     ヒント対象(ターゲット)のプレイヤ ID を指定します.

  • target_hand_index str
     ターゲットの手札の左から何番目にヒントを出したかを,0スタートで指定します.
     複数枚にヒントを出す場合は,例として 0-1-4 のように記載します.

  • color
     与える色のヒントを指定します.
     指定可能な色は,"B""G""R""W""Y" のいずれかです.

フォルダ構造

hanabiapp/
└── game/
    └── agent/
        ├── agent.py                 # AI エージェントの基底クラス(新規エージェントは必ずこのクラスを継承してください)
        ├── human_cui_agent.py       # CUI を利用した人間対戦エージェント
        ├── intentional_agent.py     # ルールベースの意図的な行動を行うエージェント
        ├── internal_state_agent.py  # 内部状態に基づくエージェント
        ├── random_agent.py          # ランダムに行動を選択するエージェント
        ├── random_agent_pyhanabi.py # pyhanabi 対応のランダムエージェント
        ├── simple_agent.py          # シンプルなヒューリスティックに基づくエージェント
        └── websocket_human_agent.py # ウェブソケットを利用した人間対戦エージェント
 1"""
 2.. include:: README.md
 3"""
 4from .intentional_agent import IntentionalAgent
 5from .internal_state_agent import InternalStateAgent
 6from .random_agent import RandomAgent
 7
 8available_ai_agents = {
 9    "InternalStateAgent": InternalStateAgent,
10    "IntentionalAgent": IntentionalAgent,
11    "RandomAgent": RandomAgent
12}
available_ai_agents = {'InternalStateAgent': <class 'hanabiapp.game.agent.internal_state_agent.InternalStateAgent'>, 'IntentionalAgent': <class 'hanabiapp.game.agent.intentional_agent.IntentionalAgent'>, 'RandomAgent': <class 'hanabiapp.game.agent.random_agent.RandomAgent'>}